#pragma once

namespace CollabRC
{
	namespace Bot
	{
		namespace AI
		{
            class ComputationalTreeNodeVisitor;

			////////////////////////////////////////////////////////////////////////////////////////////////////
			/// @class	ComputationalTreeNode
			///
			/// @brief	Defines an abstract node in a generic computational
            ///         algorithm. The node allows for genetic operations
            ///         to allow it to evolve.
			///
			/// @author	Matthew P. Del Buono
			/// @date	12/19/2009
			////////////////////////////////////////////////////////////////////////////////////////////////////
			class ComputationalTreeNode
			{
			public:
                inline virtual ~ComputationalTreeNode() { };

                /**
                 * @brief Performs the computation on this tree and returns
                 * the result
                 * @return the result of the computation
                 * @throw ComputationException if an exception, such 
                 * as division by zero, occurs during the computation
                 */
                virtual float Compute() const = 0;

                /**
                 * @brief Determines the levels of depth (levels of recursion)
                 * involved in this computation.
                 *
                 * As an example, the following tree should result in a 
                 * depth of "3":
                 * <pre>
                 * </pre>
                 * @return the depth of this tree
                 */
                virtual unsigned int GetBranchDepth() const = 0;

                /**
                 * @brief Gets a random branch from this computational tree.
                 *
                 * A branch may consist of the entire tree represented by
                 * this node all the way down to any single element at
                 * the input level into this computation. However, no
                 * branch that was not a part of the computation before
                 * (such as the right side of a LHS operation) will
                 * be selected.
                 * @param depth the number of levels deep to pull
                 * the branch. If the branch level exceeds the depth of the
                 * tree, then the depth will be bound to the maximum
                 * depth of the tree. 0 represents the current node.
                 * @return the branch that was randomly selected at the chosen
                 * depth
                 */
                virtual const ComputationalTreeNode& GetRandomBranch(unsigned int depth) const = 0;

                /**
                 * @brief Creates a ComputationalTreeNode object which is
                 * an exact computational duplicate of this ComputationalTreeNode.
                 *
                 * The duplicate ComputationalTreeNode is allocated on the
                 * heap and its address is returned. The object must be tracked
                 * by its requestor and deallocated when it is no longer needed
                 * to ensure no memory leaks occur.
                 * @return the address of the newly allocated ComputationalTreeNode
                 */
                virtual ComputationalTreeNode* Clone() const = 0;

                /**
                 * @brief Creates a ComputationalTreeNode object which is
                 * a duplicate of this ComputationalTreeNode with one
                 * random mutation. 
                 *
                 * A mutation operation either changes an operator or 
                 * a constant. Constants that change will change by a delta
                 * with an absolute value of +/- 25% or +/- 0.25, 
                 * whichever is larger.
                 *
                 * The duplicate ComputationalTreeNode is allocated on the heap
                 * and its address is returned. The object must be tracked
                 * by the caller and deallocated when it is no longer needed
                 * to ensure no memory leaks occur.
                 * @param depth the level at which the mutation operation should
                 * occur. 0 indicates this level. A depth greater than the depth
                 * of the randomly selected path results in the depth being clamped
                 * at the depth of the branch.
                 * @return the address of the newly created ComputationalTreeNode
                 * @throws IllegalMutationException if this object cannot be mutated
                 */
                virtual ComputationalTreeNode* Mutate(unsigned int depth) const = 0;

                /**
                 * @brief Executes the operation specified by the given
                 * ComputationalTreeNodeVisitor.
                 *
                 * Implementations should call an appropriate overload
                 * of ComputationalTreeNodeVisitor::Visit()
                 * @param visitor the visitor to accept
                 */
                virtual void Accept(ComputationalTreeNodeVisitor& visitor) = 0;
			};
		}
	}
}
